home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / DJLSR106.ARJ / FIX.CC < prev    next >
C/C++ Source or Header  |  1992-03-30  |  13KB  |  600 lines

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /*
  3. Copyright (C) 1989 Free Software Foundation
  4.     written by Doug Lea (dl@rocky.oswego.edu)
  5.  
  6. This file is part of the GNU C++ Library.  This library is free
  7. software; you can redistribute it and/or modify it under the terms of
  8. the GNU Library General Public License as published by the Free
  9. Software Foundation; either version 2 of the License, or (at your
  10. option) any later version.  This library is distributed in the hope
  11. that it will be useful, but WITHOUT ANY WARRANTY; without even the
  12. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  13. PURPOSE.  See the GNU Library General Public License for more details.
  14. You should have received a copy of the GNU Library General Public
  15. License along with this library; if not, write to the Free Software
  16. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. //
  19. // Fix.cc : variable length fixed point data type class functions
  20. //
  21.  
  22. #ifdef __GNUG__
  23. #pragma implementation "Fix.h"
  24. #endif
  25. #include <Fix.h>
  26. #include <std.h>
  27. #include <_Obstack.h>
  28. #include <AllocRing.h>
  29.  
  30. // default parameters
  31.  
  32. uint16 Fix_default_length = 16;
  33. int    Fix_default_print_width = 8;
  34.  
  35. Fix_peh Fix_overflow_handler = Fix_overflow_saturate;
  36.  
  37. _Frep _Frep_0    = { 16, 1, 1, { 0 } };
  38. _Frep _Frep_m1    = { 16, 1, 1, { 0x8000 } };
  39. _Frep _Frep_quotient_bump = { 16, 1, 1, { 0x4000 } };
  40.  
  41. // error handling
  42.  
  43. void default_Fix_error_handler(const char* msg)
  44. {
  45.   cerr << "Fix: " << msg << "\n";
  46.   abort();
  47. }
  48.  
  49. void default_Fix_range_error_handler(const char* msg)
  50. {
  51.   cerr << "Fix: range error in " << msg << "\n";
  52.   //abort();
  53. }
  54.  
  55. one_arg_error_handler_t 
  56.   Fix_error_handler = default_Fix_error_handler,
  57.   Fix_range_error_handler = default_Fix_range_error_handler;
  58.  
  59. one_arg_error_handler_t set_Fix_error_handler(one_arg_error_handler_t f)
  60. {
  61.   one_arg_error_handler_t old = Fix_error_handler;
  62.   Fix_error_handler = f;
  63.   return old;
  64. }
  65.  
  66. one_arg_error_handler_t set_Fix_range_error_handler(one_arg_error_handler_t f)
  67. {
  68.   one_arg_error_handler_t old = Fix_range_error_handler;
  69.   Fix_range_error_handler = f;
  70.   return old;
  71. }
  72.  
  73. void Fix::error(const char* msg)
  74. {
  75.   (*Fix_error_handler)(msg);
  76. }
  77.  
  78. void Fix::range_error(const char* msg)
  79. {
  80.   (*Fix_range_error_handler)(msg);
  81. }
  82.  
  83. // _Frep allocation and initialization functions
  84.  
  85. static inline _Fix _new_Fix(uint16 len)
  86. {
  87.   int siz = (((uint32 )len + 15) >> 4);
  88.   if (siz <= 0) siz = 1;
  89.   unsigned int allocsiz = (sizeof(_Frep) + (siz - 1) * sizeof(uint16));
  90.   _Fix z = (_Fix)(new char[allocsiz]);
  91.   bzero(z, allocsiz);
  92.   z->len = len;
  93.   z->siz = siz;
  94.   z->ref = 1;
  95.   return z;
  96. }
  97.  
  98. _Fix new_Fix(uint16 len)
  99. {
  100.   return _new_Fix(len);
  101. }
  102.  
  103. _Fix new_Fix(uint16 len, _Fix x)
  104. {
  105.   _Fix z = _new_Fix(len);
  106.   return copy(x,z);
  107. }
  108.  
  109. _Fix new_Fix(uint16 len, double d)
  110. {
  111.   _Fix z = _new_Fix(len);
  112.  
  113.   if ( d == _Fix_max_value )
  114.   {
  115.     z->s[0] = 0x7fff;
  116.     for ( int i=1; i < z->siz; i++ )
  117.       z->s[i] = 0xffff;
  118.   }
  119.   else if ( d < _Fix_min_value || d > _Fix_max_value )
  120.     (*Fix_range_error_handler)("declaration");
  121.   else
  122.   {
  123.     if (d < 0)
  124.       d += 2.0;
  125.     d *= 32768;
  126.     for ( int i=0; i < z->siz; i++ )
  127.     {
  128.       z->s[i] = (uint16 )d;
  129.       d -= z->s[i];
  130.       d *= 65536;
  131.     }
  132.     if ( d >= 32768 )
  133.       z->s[z->siz-1]++;
  134.   }
  135.   mask(z);
  136.   return z;
  137. }
  138.  
  139. // convert to a double 
  140.  
  141. double value(Fix& x)
  142.   double d = 0.0;
  143.   for ( int i=x.rep->siz-1; i >= 0; i-- )
  144.   {
  145.     d += x.rep->s[i];
  146.     d *= 1./65536.;
  147.   }
  148.   d *= 2.;
  149.   return d < 1. ? d : d - 2.;
  150. }
  151.  
  152. // extract mantissa to Integer
  153.  
  154. Integer mantissa(Fix& x)
  155. {
  156.   Integer a = 1, b=1;
  157.   for ( int i=0; i < x.rep->siz; i++ )
  158.   {
  159.     a = (a << 16) + x.rep->s[i];
  160.     b <<= 16;
  161.   }
  162.   return a-b;
  163. }
  164.  
  165. // comparison functions
  166.   
  167. inline static int docmp(uint16* x, uint16* y, int siz)
  168. {
  169.   int diff = (int16 )*x - (int16 )*y;
  170.   while ( --siz && !diff )
  171.     diff = (int32 )(uint32 )*++x - (int32 )(uint32 )*++y;
  172.   return diff;
  173. }
  174.  
  175. inline static int docmpz(uint16* x, int siz)
  176. {
  177.   while ( siz-- )
  178.     if ( *x++ ) return 1;
  179.   return 0;
  180. }
  181.  
  182. int compare(_Fix x, _Fix y)
  183. {
  184.   if ( x->siz == y->siz )
  185.     return docmp(x->s, y->s, x->siz);
  186.   else
  187.   {
  188.     int r;
  189.     _Fix longer, shorter;
  190.     if ( x->siz > y->siz )
  191.     {
  192.       longer = x;
  193.       shorter = y;
  194.       r = 1;
  195.     }
  196.     else
  197.     {
  198.       longer = y;
  199.       shorter = x;
  200.       r = -1;
  201.     }
  202.     int diff = docmp(x->s, y->s, shorter->siz);
  203.     if ( diff )
  204.       return diff;
  205.     else if ( docmpz(&longer->s[shorter->siz], longer->siz-shorter->siz) )
  206.       return r;
  207.     else
  208.       return 0;
  209.   }
  210. }
  211.  
  212. // arithmetic functions
  213.  
  214. _Fix add(_Fix x, _Fix y, _Fix r)
  215. {
  216.   uint16 xsign = x->s[0], ysign = y->s[0];
  217.   _Fix longer, shorter;
  218.   if ( x->len >= y->len )
  219.     longer = x, shorter = y;
  220.   else
  221.     longer = y, shorter = x;
  222.   if ( r == NULL )
  223.     r = new_Fix(longer->len);
  224.   for ( int i=r->siz-1; i >= longer->siz; i-- )
  225.     r->s[i] = 0;
  226.   for ( ; i >= shorter->siz; i-- )
  227.     r->s[i] = longer->s[i];
  228.   uint32 sum = 0, carry = 0;
  229.   for ( ; i >= 0; i-- )
  230.   {
  231.     sum = carry + (uint32 )x->s[i] + (uint32 )y->s[i];
  232.     carry = sum >> 16;
  233.     r->s[i] = sum;
  234.   }
  235.   if ( (xsign ^ sum) & (ysign ^ sum) & 0x8000 )
  236.     (*Fix_overflow_handler)(r);
  237.   return r;
  238. }
  239.  
  240. _Fix subtract(_Fix x, _Fix y, _Fix r)
  241. {
  242.   uint16 xsign = x->s[0], ysign = y->s[0];
  243.   _Fix longer, shorter;
  244.   if ( x->len >= y->len )
  245.     longer = x, shorter = y;
  246.   else
  247.     longer = y, shorter = x;
  248.   if ( r == NULL )
  249.     r = new_Fix(longer->len);
  250.   for ( int i=r->siz-1; i >= longer->siz; i-- )
  251.     r->s[i] = 0;
  252.   for ( ; i >= shorter->siz; i-- )
  253.     r->s[i] = (longer == x ? x->s[i] : -y->s[i]);
  254.   int16 carry = 0;
  255.   uint32 sum = 0;
  256.   for ( ; i >= 0; i-- )
  257.   {
  258.     sum = (int32 )carry + (uint32 )x->s[i] - (uint32 )y->s[i];
  259.     carry = sum >> 16;
  260.     r->s[i] = sum;
  261.   }
  262.   if ( (xsign ^ sum) & (~ysign ^ sum) & 0x8000 )
  263.     (*Fix_overflow_handler)(r);
  264.   return r;
  265. }
  266.  
  267. _Fix multiply(_Fix x, _Fix y, _Fix r)
  268. {
  269.   if ( r == NULL )
  270.     r = new_Fix(x->len + y->len);
  271.   int xsign = x->s[0] & 0x8000,
  272.     ysign = y->s[0] & 0x8000;
  273.   Fix X(x->len), Y(y->len);
  274.   if ( xsign )
  275.     x = negate(x,X.rep);
  276.   if ( ysign )
  277.     y = negate(y,Y.rep);
  278.   for ( int i=0; i < r->siz; i++ )
  279.     r->s[i] = 0;
  280.   for ( i=x->siz-1; i >= 0; i-- )
  281.   {
  282.     uint32 carry = 0;
  283.     for ( int j=y->siz-1; j >= 0; j-- ) 
  284.     {
  285.       int k = i + j + 1;
  286.       uint32 a = (uint32 )x->s[i] * (uint32 )y->s[j];
  287.       uint32 b = ((a << 1) & 0xffff) + carry;
  288.       if ( k < r->siz )
  289.       {
  290.     b += r->s[k];
  291.         r->s[k] = b;
  292.       }
  293.       if ( k < r->siz + 1 )
  294.         carry = (a >> 15) + (b >> 16);
  295.     }
  296.     r->s[i] = carry;
  297.   }
  298.   if ( xsign != ysign )
  299.     negate(r,r);
  300.   return r;
  301. }
  302.  
  303. _Fix multiply(_Fix x, int y, _Fix r)
  304. {
  305.   if ( y != (int16 )y )
  306.     (*Fix_range_error_handler)("multiply by int -- int too large");
  307.   if ( r == NULL )
  308.     r = new_Fix(x->len);
  309.   for ( int i=r->siz-1; i >= x->siz; i-- )
  310.     r->s[i] = 0;
  311.   int32 a, carry = 0;
  312.   for ( ; i > 0; i-- )
  313.   {
  314.     a = (int32 )(uint32 )x->s[i] * y + carry;
  315.     r->s[i] = a;
  316.     carry = a >> 16;        // assumes arithmetic right shift
  317.   }
  318.   a = (int32 )(int16 )x->s[0] * y + carry;
  319.   r->s[0] = a;
  320.   a &= 0xffff8000L;
  321.   if ( a != 0xffff8000L && a != 0L ) {
  322.     r->s[0] = 0x8000 ^ x->s[0] ^ y;
  323.     (*Fix_overflow_handler)(r);
  324.   }
  325.   return r;
  326. }
  327.  
  328. _Fix divide(_Fix x, _Fix y, _Fix q, _Fix r)
  329. {
  330.   int xsign = x->s[0] & 0x8000, 
  331.     ysign = y->s[0] & 0x8000;
  332.   if ( q == NULL )
  333.     q = new_Fix(x->len);
  334.   copy(&_Frep_0,q);
  335.   if ( r == NULL )
  336.     r = new_Fix(x->len + y->len - 1);
  337.   if ( xsign )
  338.     negate(x,r);
  339.   else
  340.     copy(x,r);
  341.   Fix Y(y->len);
  342.   y = ( ysign ? negate(y,Y.rep) : copy(y,Y.rep) );
  343.   if ( !compare(y) )
  344.     (*Fix_range_error_handler)("division -- division by zero");
  345.   else if ( compare(x,y) >= 0 )
  346.     if ( compare(x,y) == 0 && (xsign ^ ysign) != 0 )
  347.     {
  348.       copy(&_Frep_m1,q);
  349.       copy(&_Frep_0,r);
  350.     }
  351.     else
  352.       (*Fix_range_error_handler)("division");
  353.   else
  354.   {
  355.     _Fix t;
  356.     Fix S(r->len),
  357.       W(q->len,&_Frep_quotient_bump);
  358.     for ( int i=1; i < q->len; i++ )
  359.     {
  360.       shift(y,-1,y);
  361.       subtract(r,y,S.rep);
  362.       int s_status = compare(S.rep);
  363.       if ( s_status == 0 ) 
  364.       {
  365.     t = r, r = S.rep, S.rep = t;
  366.     break;
  367.       }
  368.       else if ( s_status > 0 )
  369.       {
  370.     t = r, r = S.rep, S.rep = t;
  371.     add(q,W.rep,q);
  372.       }
  373.       shift(W.rep,-1,W.rep);
  374.     }
  375.     if ( xsign ^ ysign )
  376.       negate(q,q);
  377.   }
  378.   return q;
  379. }
  380.  
  381. _Fix shift(_Fix x, int y, _Fix r)
  382. {
  383.   if ( y == 0 )
  384.     return x;
  385.   else if ( r == NULL )
  386.     r = new_Fix(x->len);
  387.  
  388.   int ay = abs((long) y),
  389.     ayh = ay >> 4,
  390.     ayl = ay & 0x0f;
  391.   int xl, u, ilow, ihigh;
  392.   uint16 *rs, *xsl, *xsr;
  393.  
  394.   if ( y > 0 )
  395.   {
  396.     rs = r->s;
  397.     xsl = x->s + ayh;
  398.     xsr = xsl + 1;
  399.     xl = ayl;
  400.     u = 1;
  401.     ihigh = x->siz - ayh - 1;
  402.     ilow = 0;
  403.   }
  404.   else
  405.   {
  406.     rs = &r->s[r->siz - 1];
  407.     xsr = &x->s[r->siz - 1] - ayh;
  408.     xsl = xsr - 1;
  409.     xl = 16 - ayl;
  410.     u = -1;
  411.     ihigh = r->siz - ayh - 1;
  412.     ilow = ihigh - x->siz;
  413.   }
  414.  
  415.   int xr = 16 - xl;
  416.   uint16 xrmask = 0xffffL >> xr;
  417.   for ( int i=0; i < ilow; i++, rs+=u, xsl+=u, xsr+=u )
  418.     *rs = 0;
  419.   for ( ; i < ihigh; i++, rs+=u, xsl+=u, xsr+=u )
  420.     *rs = (*xsl << xl) + ((*xsr >> xr) & xrmask);
  421.   *rs = (y > 0 ? (*xsl << xl) : ((*xsr >> xr) & xrmask));
  422.   rs += u;
  423.   for ( ; ++i < r->siz; rs+=u )
  424.     *rs = 0;
  425.   return r;
  426. }
  427.  
  428. _Fix negate(_Fix x, _Fix r)
  429. {
  430.   if ( r == NULL )
  431.     r = new_Fix(x->len);
  432.   uint32 carry = 1;
  433.   for ( int i=r->siz-1; i >= x->siz; i-- )
  434.     r->s[i] = 0;
  435.   for ( ; i >= 0; i-- )
  436.   {
  437.     uint32 a = (uint16 )~x->s[i] + carry;    // bug work-around
  438.     r->s[i] = a;
  439.     carry = a >> 16;
  440.   }
  441.   return r;
  442. }
  443.  
  444. // io functions
  445.  
  446. Fix atoF(const char* a, int len)
  447. {
  448.   return Fix(len,atof(a));
  449. }
  450.  
  451. extern AllocRing _libgxx_fmtq;
  452.  
  453. char* Ftoa(Fix& x, int width)
  454. {
  455.   int wrksiz = width + 2;
  456.   char *s = (char *) _libgxx_fmtq.alloc(wrksiz);
  457.   char format[100];
  458.   double val = value(x);
  459.   if (val < 0)
  460.     sprintf(format,"%%%d.%dlf",width-2,width-3);
  461.   else
  462.     sprintf(format," %%%d.%dlf",width-2,width-3);
  463.   sprintf(s,format,val);
  464.   return s;
  465. }
  466.  
  467. extern Obstack _libgxx_io_ob;
  468.  
  469. Fix Fix::operator %= (int y)
  470. {
  471.   Fix r((int )rep->len + y, *this); return *this = r;
  472. }
  473.  
  474. istream& operator >> (istream& s, Fix& y)
  475. {
  476.   int got_one = 0;
  477. #ifdef _OLD_STREAMS
  478.   if (!s.good())
  479.   {
  480.     return s;
  481.   }
  482. #else
  483.   if (!s.ipfx(0))
  484.   {
  485.     s.set(ios::failbit); // Redundant if using GNU iostreams.
  486.     return s;
  487.   }
  488. #endif
  489.  
  490.   char sign = 0, point = 0;
  491.   char ch;
  492.   s >> ws;
  493.   if (!s.good())
  494.   {
  495.     s.set(_fail);
  496.     return s;
  497.   }
  498.   while (s.get(ch))
  499.   {
  500.     if (ch == '-')
  501.     {
  502.       if (sign == 0)
  503.       {
  504.         sign = 1;
  505.         _libgxx_io_ob.grow(ch);
  506.       }
  507.       else
  508.         break;
  509.     }
  510.     if (ch == '.')
  511.     {
  512.       if (point == 0)
  513.       {
  514.         point = 1;
  515.         _libgxx_io_ob.grow(ch);
  516.       }
  517.       else
  518.         break;
  519.     }
  520.     else if (ch >= '0' && ch <= '9')
  521.     {
  522.       got_one = 1;
  523.       _libgxx_io_ob.grow(ch);
  524.     }
  525.     else
  526.       break;
  527.   }
  528.   char * p = (char*)(_libgxx_io_ob.finish(0));
  529.   if (s.good())
  530.     s.putback(ch);
  531.   if (!got_one)
  532.     s.set(_fail);
  533.   else
  534.     y = atoF(p);
  535.   _libgxx_io_ob.free(p);
  536.   return s;
  537. }
  538.  
  539. void show(Fix& x)
  540. {
  541.   cout << "len = " << x.rep->len << "\n";
  542.   cout << "siz = " << x.rep->siz << "\n";
  543.   cout << "ref = " << x.rep->ref << "\n";
  544.   cout << "man = " << Itoa(mantissa(x),16,4*x.rep->siz) << "\n";
  545.   cout << "val = " << value(x) << "\n";
  546. }
  547.  
  548. // parameter setting operations
  549.  
  550. Fix_peh set_overflow_handler(Fix_peh new_handler) {
  551.   Fix_peh old_handler = Fix_overflow_handler;
  552.   Fix_overflow_handler = new_handler;
  553.   return old_handler;
  554. }
  555.  
  556. int Fix_set_default_length(int newlen)
  557. {
  558.   uint16 oldlen = Fix_default_length;
  559.   if ( newlen < _Fix_min_length || newlen > _Fix_max_length )
  560.     (*Fix_error_handler)("illegal length in Fix_set_default_length");
  561.   Fix_default_length = newlen;
  562.   return oldlen;
  563. }
  564.  
  565. // overflow handlers
  566.  
  567. void Fix_overflow_saturate(_Fix& r) {
  568.   if ( (int16 )r->s[0] > 0 ) 
  569.   {
  570.     r->s[0] = 0x8000;
  571.     for ( int i=1; i < r->siz; i++ )
  572.       r->s[i] = 0;
  573.   }
  574.   else
  575.   {
  576.     r->s[0] = 0x7fff;
  577.     for ( int i=1; i < r->siz; i++ )
  578.       r->s[i] = 0xffff;
  579.     mask(r);
  580.   }
  581. }
  582.  
  583. void Fix_overflow_wrap(_Fix& r) {}
  584.  
  585. void Fix_overflow_warning_saturate(_Fix& r) {
  586.   Fix_overflow_warning(r);
  587.   Fix_overflow_saturate(r);
  588. }
  589.  
  590. void Fix_overflow_warning(_Fix& r) {
  591.   cerr << "Fix: overflow warning\n"; 
  592. }
  593.  
  594. void Fix_overflow_error(_Fix& r) {
  595.   cerr << "Fix: overflow error\n"; 
  596.   abort();
  597. }
  598.  
  599.